#include "tbag.h"
#include <assert.h>
#include "stdafx.h"

namespace Taskbag {
	TBag::TBag(int num_prc,int argc, char* argv[]){
		nproc=num_prc;
		task=new Task*[nproc];
		thread=new HANDLE[nproc];
		InitializeCriticalSection(&cs);
	}

	TBag::~TBag(){
		delete task;
		delete thread;
		DeleteCriticalSection(&cs);
	}

	void TBag::run(){
		DWORD id;
		cur_task=0;
		c_active=0;
		for(int i=0;i<nproc;i++){
			thread[i]=CreateThread(NULL,0,tFunc,this,0,&id);
			task[i]=createTask();
			assert(thread[i]&&task[i]);
		}
		await=CreateEvent(NULL,FALSE,FALSE,NULL);//auto,non-signaled
		assert(await);
		WaitForMultipleObjects(nproc,thread,TRUE,INFINITE);
		for(int i=0;i<nproc;i++){
			CloseHandle(thread[i]);
			delete task[i];
		}
		CloseHandle(await);
	}

	DWORD WINAPI tFunc(LPVOID p){
		TBag* b=(TBag*)p;
		TBag::Task* task;

		EnterCriticalSection(&b->cs);
		task=b->task[b->cur_task++];
		for(;;){
			while(!b->if_job()){
				if(!b->c_active){
					SetEvent(b->await);
					LeaveCriticalSection(&b->cs);
					return 0;
				}
				LeaveCriticalSection(&b->cs);
				WaitForSingleObject(b->await,INFINITE);
				EnterCriticalSection(&b->cs);
			}
			b->get(task);
			b->c_active++;
			LeaveCriticalSection(&b->cs);

			b->proc(task);
		
			EnterCriticalSection(&b->cs);
			b->c_active--;
			b->put(task);
			SetEvent(b->await);
		}
		return 0;
	}
}